<?php
/**
 * Created by PhpStorm.
 * User: Anders
 * Date: 2018/12/22
 * Time: 15:35
 */

namespace App\Models;


trait Query
{
    /**
     * datatables通用数据
     * @param        $request
     * @param string $qField
     * @param string $between
     * @return array
     */
    public function list($request, string $qField, string $between = 'updated_at')
    {
        //搜索关键字
        $kw = $request->get('kw');
        $map = [];
        if (!empty($kw)) {
            $map[] = [$qField, 'like', "%{$kw}%"];
        }
        // 日期区间
        $min = $request->get('logmin');
        if (empty($min)) {
            $min = date('Y-m-d', time() - 24 * 3600);
        }
        $min .= ' 00:00:00';
        $max = $request->get('logmax');
        if (empty($max)) {
            $max = date('Y-m-d', time());
        }
        $max .= ' 23:59:59';

        // 排序
        $order = $request->get('order')[0];
        $column = $order['column'];
        $columns = $request->get('columns');
        $field = $columns[$column]['data'];
        $dir = $order['dir'];
        // 偏移
        $offset = $request->get('start');
        // 每页多少
        $limit = $request->get('length');

        $data = $this->where($map)->whereBetween($between, [$min, $max]);

        return [
            'draw' => $request->get('draw'),
            'recordsTotal' => $data->count(),
            'recordsFiltered' => $data->count(),
            'data' => $data->offset($offset)->limit($limit)->orderBy($field, $dir)->withTrashed()->get()
        ];
    }

    /**
     * TODO:: 怎样设置过期时间？？？
     * 防止缓存穿透的查询方法
     * @param string $prefix
     * @param int $id
     * @return null|object
     */
    public function getDataFromCache(string $prefix, int $id)
    {
        // Redis模块提供redis与redis.connection这两个服务；
        // redis.connection服务提供redis连接对象；
        // redis服务提供Illuminate\Redis\RedisManager对象，负责与Redis打交道的这部分管理工作；
        $redis = app('redis.connection');
        // 获取访问者IP
        $ip = request()->ip();
        $lip = 'l' . substr($ip, 0, strrpos($ip, '.'));
        // 查找该IP在list中的次数
        $lipCount = $redis->llen($lip);
        // 如果超过.env（IP_SEGMENT_COUNT）设置的阈值，封杀IP段，跳到404
        $ip_segment_count = env('IP_SEGMENT_COUNT', 50);
        if ($lipCount >= $ip_segment_count) return null;


        // 定义 单ip次数 在redis中的键名
        $ipKey = 'ip' . $ip;
        // 单IP在出现的次数
        $ipCount = $redis->get($ipKey);
        //查询ip的异常访问次数是否达到阈值
        $ip_count = env('IP_COUNT', 10);
        if ($ipCount >= $ip_count) {
            //看看ip是否已经在list中
            $lipArr = $redis->lRange($lip, 0, -1);
            if (array_search($ip, $lipArr) === false) {
                // ip追加到封杀IP段的list中
                $redis->lpush($lip, $ip);
                // 缓存有效期
                $timeout = env('IP_TIMEOUT', 3600);
                // 设置缓存有效期
                $redis->setTimeout($lip, $timeout);
            }
            return null;
        }

        // 待查询的键
        $searchKey = $prefix . ':' . $id;
        //检查是否在缓存中
        $cacheHash = $redis->hGetAll($searchKey);
        //如果缓存不存在
        //在redis中添加一个string类型的key，保存ip的异常访问次数
        if (empty($cacheHash)) {
            //去数据库中查找
            $data = $this->find($id)->toArray();
            if (!$data) {
                //数据库没有数据，权重为2 TODO::在env文件配置
                $redis->incrBy($ipKey, 2);
                $redis->setTimeout($ipKey, 30);
                $redis->hMSet($searchKey, [-1]);
                $redis->setTimeout($searchKey, 60);
                return null;
            }
            // 有数据，缓存起来
            $redis->hMSet($searchKey, $data);
            $redis->setTimeout($searchKey, 60);
        } elseif ($cacheHash == [-1]) {
            // 权重为1
            $redis->incr($ipKey);
            // 30秒过期
            $redis->setTimeout($ipKey, 30);
            return null;
        }
        return $cacheHash;
    }

    /**
     * 新增|删除数据，id要添加到redis队列中
     * @param int $id
     * @param string $mark
     * @param string $db
     */
    public function redisListId(int $id, string $mark,string $db)
    {
        // 转成json
        $json = json_encode(['id' => $id, 'mark' => $mark, 'db' => $db]);
        $redis = new \Redis();
        $redis->connect('127.0.0.1');
        $redis->auth('qazzaq123');
        $redis->rPush('id_list', $json);
    }
}